/**
 * 函数防抖 (只执行最后一次点击)
 * @param fn
 * @param delay
 * @returns {Function}
 * @constructor
 */
export const Debounce = (fn, t) => {
  const delay = t || 300
  let timer
  return function() {
    const args = arguments
    if (timer) {
      clearTimeout(timer)
    }
    timer = setTimeout(() => {
      timer = null
      fn.apply(this, args)
    }, delay)
  }
}
/**
 * 函数节流
 * @param fn
 * @param interval
 * @returns {Function}
 * @constructor
 */
export const Throttle = (fn, t) => {
  let last
  let timer
  const interval = t || 500
  return function() {
    const args = arguments
    const now = +new Date()
    if (last && now - last < interval) {
      clearTimeout(timer)
      timer = setTimeout(() => {
        last = now
        fn.apply(this, args)
      }, interval)
    } else {
      last = now
      fn.apply(this, args)
    }
  }
}

/**
 * url参数解析
 * @param url
 * @returns {obj}
 */
export const queryURLParams = function(variable = window.location.href) {
  const obj = {}
  variable.replace(
    /([^?=&#]+)=([^?&#]+)/g,
    (_, key, value) => (obj[key] = value)
  )
  variable.replace(/#([^?=&#]+)/g, (_, hash) => (obj['HASH'] = hash))
  return obj
}

/**
 * 统计图y轴数据格式化
 * @param v
 * @returns {Function}
 */
export const flargeNum = function(num) {
  num = Math.abs(num) > 10000 ? (num / 10000).toFixed(0) + 'w' : num
  return num
}

/**
 * 统计图x轴日期数据格式化 xxxx-xx-xx -> xx/xx
 * @param v
 * @returns {Function}
 */
export const fdate = function(v) {
  const dateArr = v.split('-')
  return dateArr[1] + '/' + dateArr[2]
}

/**
 *  深拷贝
 * @param {*} obj
 * @returns {obj}
 */
// 判断边界， null 这个特殊情况
const isObject = obj => typeof obj === 'object' && obj !== null
// 递归实现深拷贝
export const deepClone = function(source, hash = new WeakMap()) {
  if (!isObject(source)) return source // 非对象返回自身
  if (hash.has(source)) return hash.get(source) // 新增检测, 查哈希表
  const target = Array.isArray(source) ? [] : {}
  hash.set(source, target) // 设置哈希表值
  for (const key in source) {
    if (Object.prototype.hasOwnProperty.call(source, key)) {
      target[key] = isObject(source[key])
        ? deepClone(source[key], hash)
        : source[key] // 传入哈希表
    }
  }
  return target
}

/**
 * @name: 计算方法 解决小数计算精度丢失问题
 * @param {Number} a
 * @param {Number} b
 * @param {String} op  (+ || - || * || /)
 * @return {Number} (a op b)
 */
export const operate = function(a, b, op) {
  const d1 = toInt(a)
  const d2 = toInt(b)
  const max = d1.times > d2.times ? d1.times : d2.times
  let rel
  switch (op) {
    case '+':
      rel = (d1.num * max + d2.num * max) / max
      break
    case '-':
      rel = (d1.num * max - d2.num * max) / max
      break
    case '*':
      rel = (d1.num * max * (d2.num * max)) / (max * max)
      break
    case '/':
      rel = (d1.num * max) / (d2.num * max)
      break
  }
  return rel
}

/**
 * @name: 浮点数转换为整数
 * @param {Number} num
 * @return {Object}
 */
function toInt(num) {
  const rel = {}
  const str = num < 0 ? -num + '' : num + ''
  const pos = str.indexOf('.')
  const len = str.substr(pos + 1).length
  const times = Math.pow(10, len + 1) // 补充：当小数位数较多时，避免出错，所以多扩大一倍，提高精度
  rel.times = times
  rel.num = num
  return rel
}

/**
 * @name: 修复toFixed四舍五入问题
 * @param {Number} d    保留位数
 * @return {String}
 */
export const toFixed = function(d) {
  let s = this + ''
  if (!d) d = 0
  if (s.indexOf('.') === -1) s += '.'
  s += new Array(d + 1).join('0')
  if (new RegExp('^(-|\\+)?(\\d+(\\.\\d{0,' + (d + 1) + '})?)\\d*$').test(s)) {
    let s = '0' + RegExp.$2
    const pm = RegExp.$1
    let a = RegExp.$3.length
    let b = true
    if (a === d + 2) {
      a = s.match(/\d/g)
      if (parseInt(a[a.length - 1]) > 4) {
        for (let i = a.length - 2; i >= 0; i--) {
          a[i] = parseInt(a[i]) + 1
          if (a[i] === 10) {
            a[i] = 0
            b = i !== 1
          } else break
        }
      }
      s = a.join('').replace(new RegExp('(\\d+)(\\d{' + d + '})\\d$'), '$1.$2')
    }
    if (b) s = s.substr(1)
    return (pm + s).replace(/\.$/, '')
  }
  return this + ''
}

// 获取v天前日期
export const getDateBynum = function(v) {
  const dd = new Date()
  dd.setDate(dd.getDate() + v) // 获取v天后的日期
  const y = dd.getFullYear()
  const m = dd.getMonth() + 1 < 10 ? '0' + (dd.getMonth() + 1) : dd.getMonth() + 1 // 获取当前月份的日期，不足10补0
  const d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate() // 获取当前几号，不足10补0
  return y + '-' + m + '-' + d
}
